# -*- coding: utf-8 -*-
import os
import platform
import re
import subprocess
import sys
from enum import IntEnum
from random import choice
from configparser import ConfigParser

rHEX = lambda: "#" + "".join([choice('0123456789ABCDEF') for _ in range(6)])
symbolName = ['o', 's', 'd', '+', 't', 't1', 't2', 't3', 'p', 'h', 'star', 'x', 'arrow_up', 'arrow_right', 'arrow_down',
              'arrow_left', 'crosshair']
symbolChar = ['○', '▢', '◇', '+', '▽', '△', '▷', '◁', '⬠', '⬡', '☆', '⨯', '↑', '→', '↓', '←', '⊕']
symbolChar2Name = dict(zip(symbolChar, symbolName))


class SettingParams:
    def __init__(self):
        # Information
        self.recent_folder = ''
        self.file_filter = 'All Supported Files (*.csv *.xlsx *.pkl);;All Files (*.*)'

        # General
        self.language = 'English'
        self.font_path = ''
        self.parametric_map = True
        self.parametric_hbin = True
        self.parametric_sbin = True
        self.hfont_size = 12
        self.sfont_size = 12
        self.wfont_size = 12

        # stand
        self.long = '65651'
        self.pass_bin = '1'

        # bin
        # self.siteColor = {}
        self.hColor = {}
        self.sColor = {}

        # trend
        self.showMedian_trend = True
        self.showHL_trend = True
        self.showHSpec_trend = True
        self.showLL_trend = True
        self.showLSpec_trend = True
        self.showMean_trend = True
        self.xCoord_color = ""
        self.yCoord_color = ""
        self.xCoord_symbol = ""
        self.yCoord_symbol = ""
        self.trend_dict = {}
        self.num_coord = ['XCoord', 'YCoord']
        self.trend_width = {"mean": 3, "median": 3, "llimit": 3, "hlimit": 3, "lspec": 3, "hspec": 3}
        self.wafer_dict = {}
        self.wafer_la = 0
        self.wafer_lv = 0
        self.wafer_ha = 0
        self.wafer_hv = 0
        self.wafer_precision_mA = 3
        self.wafer_precision_mV = 3
        self.wafer_precision = {"mA": self.wafer_precision_mA, "mV": self.wafer_precision_mV}
        self.wafer_split = 5
        self.wafer_invert = {0: {'x': False, 'y': False}, 1: {'x': False, 'y': True},
                             2: {'x': True, 'y': True}, 3: {'x': True, 'y': False}}
        self.wafer_origin_index = 0
        self.wafer_units = {0: 'A', 1: 'mA', 2: 'nA', 3: 'uA', 4: 'V', 5: 'mV', 6: 'nV', 7: 'uV'}
        self.wafer_select_A = 0
        self.wafer_select_V = 0

def is_valid_hex(s):
    # 确保字符串正好包含两个0-9和a-f/A-F的字符
    pattern = r'^[0-9A-Fa-f]{2}$'
    return bool(re.match(pattern, s))

def extract_value_and_unit(input_string):
    # 正则表达式匹配必须有一个数值和一个单位
    regex = r'^([+-]?\d*\.?\d+)\s*(mV|mA|uA|nA|A|uV|nV|V|%|%)$'
    match = re.match(regex, input_string)

    if match:
        # 第一个括号匹配的是数值部分
        value = float(match.group(1))
        # 第二个括号匹配的是单位部分
        unit = match.group(2)

        return {"value": value, "unit": unit}
    else:
        # 如果输入格式不匹配，则返回None或其他适当的错误处理
        return None

class tab(IntEnum):
    INFO = 0
    BIN = 1
    CATE = 2
    SUMMARY = 3
    MAP = 4
    TREND = 5
    WAFER_SUMMARY = 6


def loadFonts():
    """加载字体"""
    directory_path = os.path.join(sys.rootFolder, "src", "fonts")
    fonts = []
    for fn in os.listdir(directory_path):
        if not fn.endswith(".ttf"): continue
        fontPath = os.path.join(directory_path, fn)
        fonts.append(fontPath)
    return fonts




GlobalSetting = SettingParams()
conf = ConfigParser()  # 需要实例化一个ConfigParser对象


def getSetting() -> SettingParams:
    return GlobalSetting



def get_file_size(p: str) -> str:
    """获得文件大小"""
    try:
        return "%.2f MB" % (os.stat(p).st_size / 2 ** 20)
    except Exception:
        return "?? MB"
    except SystemExit:
            pass
def readConfigFile():
    """
    参考：https://blog.csdn.net/qdPython/article/details/120225316
    读取配置文件
    :return:
    """
    global GlobalSetting
    global conf

    conf.read(sys.CONFIG_PATH)  # 需要添加上config.ini的路径，不需要open打开，直接给文件路径就读取，也可以指定encoding='utf-8'
    GlobalSetting.recent_folder = conf['Information']['recent_folder']
    GlobalSetting.file_filter = conf['Information']['file_filter']
    GlobalSetting.language = conf['General']['language']
    GlobalSetting.font_path = conf['General']['font_path']
    GlobalSetting.pass_bin = conf['stand']['pass_bin']
    boolean = {"True": True, "False": False}
    GlobalSetting.parametric_map = boolean[conf['General']['parametric_map']]
    GlobalSetting.parametric_hbin = boolean[conf['General']['parametric_hbin']]
    GlobalSetting.parametric_sbin = boolean[conf['General']['parametric_sbin']]
    GlobalSetting.showMedian_trend = boolean[conf['Trend']['showMedian_trend']]
    GlobalSetting.showHL_trend = boolean[conf['Trend']['showHL_trend']]
    GlobalSetting.showHSpec_trend = boolean[conf['Trend']['showHSpec_trend']]
    GlobalSetting.showLL_trend = boolean[conf['Trend']['showLL_trend']]
    GlobalSetting.showLSpec_trend = boolean[conf['Trend']['showLSpec_trend']]
    GlobalSetting.showMean_trend = boolean[conf['Trend']['showMean_trend']]
    GlobalSetting.xCoord_color = conf['Trend']['xCoord_color']
    GlobalSetting.yCoord_color = conf['Trend']['yCoord_color']
    GlobalSetting.xCoord_symbol = conf['Trend']['xCoord_symbol']
    GlobalSetting.yCoord_symbol = conf['Trend']['yCoord_symbol']

    GlobalSetting.wafer_la = float(conf['stand']['la'])
    GlobalSetting.wafer_ha = float(conf['stand']['ha'])
    GlobalSetting.wafer_lv = float(conf['stand']['lv'])
    GlobalSetting.wafer_hv = float(conf['stand']['hv'])
    GlobalSetting.wafer_precision_mA = int(conf['stand']['wafer_precision_ma'])
    GlobalSetting.wafer_precision_mV = int(conf['stand']['wafer_precision_mv'])
    GlobalSetting.wafer_select_A = int(conf['stand']['wafer_select_A'])
    GlobalSetting.wafer_select_V = int(conf['stand']['wafer_select_V'])
    GlobalSetting.wafer_split = int(conf['stand']['wafer_split'])
    GlobalSetting.sfont_size = int(conf['General']['sfont_size'])
    GlobalSetting.wfont_size = int(conf['General']['wfont_size'])
    GlobalSetting.hfont_size = int(conf['General']['hfont_size'])
    GlobalSetting.wafer_origin_index = int(conf['stand']['wafer_origin_index'])
    GlobalSetting.wafer_precision = {"mA": GlobalSetting.wafer_precision_mA, "mV": GlobalSetting.wafer_precision_mV}


    hColor = {}
    # bin chart
    for key in conf['bin_color']:
        hColor[key] = conf['bin_color'][key]
    GlobalSetting.hColor = hColor

    sColor = {}
    # bin chart
    for key in conf['cate_color']:
        sColor[key] = conf['cate_color'][key]
    GlobalSetting.sColor = sColor
    trend = {}
    for key in conf['trend_color']:
        trend[key] = conf['trend_color'][key]
    GlobalSetting.trend_dict = trend
    wafer = {}
    for key in conf['wafer_color']:
        wafer[key] = conf['wafer_color'][key]
    GlobalSetting.wafer_dict = wafer

    trend_width = {}

    for key in conf['trend_width']:
        trend_width[key] = int(conf['trend_width'][key])
    GlobalSetting.trend_width = trend_width



def saveConfigFile():
    conf['Information']['recent_folder'] = GlobalSetting.recent_folder
    conf['Information']['file_filter'] = GlobalSetting.file_filter
    conf['General']['language'] = GlobalSetting.language
    conf['General']['font_path'] = GlobalSetting.font_path
    conf['stand']['pass_bin'] = GlobalSetting.pass_bin
    conf['General']['parametric_map'] = str(GlobalSetting.parametric_map)
    conf['General']['parametric_hbin'] = str(GlobalSetting.parametric_hbin)
    conf['General']['parametric_sbin'] = str(GlobalSetting.parametric_sbin)

    conf['Trend']['showMedian_trend'] = str(GlobalSetting.showMedian_trend)
    conf['Trend']['showHL_trend'] = str(GlobalSetting.showHL_trend)
    conf['Trend']['showHSpec_trend'] = str(GlobalSetting.showHSpec_trend)
    conf['Trend']['showLL_trend'] = str(GlobalSetting.showLL_trend)
    conf['Trend']['showLSpec_trend'] = str(GlobalSetting.showLSpec_trend)
    conf['Trend']['showMean_trend'] = str(GlobalSetting.showMean_trend)
    conf['Trend']['xCoord_color'] = GlobalSetting.xCoord_color
    conf['Trend']['yCoord_color'] = GlobalSetting.yCoord_color
    conf['Trend']['xCoord_symbol'] = GlobalSetting.xCoord_symbol
    conf['Trend']['yCoord_symbol'] = GlobalSetting.yCoord_symbol

    conf['stand']['la'] = str(GlobalSetting.wafer_la)
    conf['stand']['ha'] = str(GlobalSetting.wafer_ha)
    conf['stand']['lv'] = str(GlobalSetting.wafer_lv)
    conf['stand']['hv'] = str(GlobalSetting.wafer_hv)
    conf['stand']['wafer_precision_ma'] = str(GlobalSetting.wafer_precision_mA)
    conf['stand']['wafer_precision_mv'] = str(GlobalSetting.wafer_precision_mV)
    conf['stand']['wafer_select_V'] = str(GlobalSetting.wafer_select_V)
    conf['stand']['wafer_select_A'] = str(GlobalSetting.wafer_select_A)
    conf['stand']['wafer_split'] = str(GlobalSetting.wafer_split)
    conf['General']['sfont_size'] = str(GlobalSetting.sfont_size)
    conf['General']['wfont_size'] = str(GlobalSetting.wfont_size)
    conf['General']['hfont_size'] = str(GlobalSetting.hfont_size)
    conf['stand']['wafer_origin_index'] = str(GlobalSetting.wafer_origin_index)

    for key in GlobalSetting.hColor.keys():
        conf['bin_color'][key] = GlobalSetting.hColor[key]

    for key in GlobalSetting.sColor.keys():
        conf['cate_color'][key] = GlobalSetting.sColor[key]

    for key in GlobalSetting.trend_dict.keys():
        conf['trend_color'][key] = GlobalSetting.trend_dict[key]

    for key in GlobalSetting.trend_width.keys():
        conf['trend_width'][key] = str(GlobalSetting.trend_width[key])

    for key in GlobalSetting.wafer_dict.keys():
        conf['wafer_color'][key] = str(GlobalSetting.wafer_dict[key])

    with open(sys.CONFIG_PATH, 'w') as f:
        conf.write(f)


def revealFile(filepath: str) -> None:
    filepath = os.path.normpath(filepath)
    if platform.system() == 'Darwin':  # macOS
        subprocess.call(('open', '-R', filepath))
    elif platform.system() == 'Windows':  # Windows
        subprocess.call(f'explorer /select,"{filepath}"', creationflags= \
            subprocess.CREATE_NO_WINDOW | subprocess.DETACHED_PROCESS)
    else:  # linux variants
        subprocess.call(('xdg-open', os.path.dirname(filepath)))


def parseTestString(test_name_string: str, isWaferName: bool = False) -> tuple:
    '''
    Parse string from
        `TestSelection` UI into (test num, pmr index, test name)
        `WaferSelection` UI into (wafer index, file id, wafer name)
    '''
    if isWaferName:
        # split up to 2 elements
        tmpList = test_name_string.split("\t", 1)
        waferIndex = -1
        fid = -1
        wafer_name = tmpList[-1]

        if tmpList[0] == "-":
            # stacked wafer, use default value
            pass
        else:
            # other have a pattern "File{}-#{}"
            fileStr, waferindStr = tmpList[0].split("-")
            waferIndex = int(waferindStr.strip("#"))
            fid = int(fileStr.strip("File"))

        return (waferIndex, fid, wafer_name)

    else:
        # split up to 3 elements
        tmpList = test_name_string.split("\t", 2)
        test_num = int(tmpList[0])
        # set default PMR index to 0
        pmr = 0
        test_name = tmpList[-1]

        if len(tmpList) > 2:
            # a possible MPR test, e.g. [test num, #PMR, test name]
            # try to conver to int
            try:
                pmr = int(tmpList[1].strip("#"))
            except ValueError:
                # if failed, means the orignal test name
                # has the pattern of "#%s\t%s"
                test_name = f"{tmpList[1]}\t{test_name}"

        return (test_num, pmr, test_name)
